package com.transfiguro.converters;

import com.transfiguro.datamodel.ClassType;
import com.transfiguro.datamodel.csmodels.*;
import com.transfiguro.datamodel.javamodels.*;
import com.transfiguro.exceptions.ConversionFailedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * An implementation of {@link Dispatcher}. This class has methods to handle specific
 * kinds of <code>JavaModels</code>
 */
public class JDispatcher implements Dispatcher {
    private final Logger logger = LoggerFactory.getLogger(JDispatcher.class);

    /**
     * Provided for future use
     */
    public void dispatch() {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    /**
     * This method calls converters for various variables in a given {@link ClassModel}
     *
     * @param model  The <code>ClassModel</code> to be converted
     * @return  An instance of <code>CSClassModel</code> created by
     *         converting the given <code>ClassModel</code>
     */
    public CSClassModel dispatch(final ClassModel model) {
        CSClassModel csClassModel = new CSClassModel();
        if (model.getClassType().equals(ClassType.BASECLASS)) {
            List<CSMethod> csMethodList = new ArrayList<CSMethod>();
            List<CSVariable> csVariableList = new ArrayList<CSVariable>();
            Imports imports = model.getImports();
            logger.info("Imports: {}", imports.toString());
            final BaseClassConverter baseClassConverter = new BaseClassConverter(model);
            try {
                if (baseClassConverter.convert()) {
                    csClassModel = baseClassConverter.getCsClassModel();
                    if (imports.getImports() != null) {
                        csClassModel.setUsings(this.dispatch(imports));
                    }
                    for (final Method method : model.getMethods()) {
                        csMethodList.add(this.dispatch(method));
                    }
                    for (final Variable variable : model.getVariables()) {
                        csVariableList.add(this.dispatch(variable));
                    }
                    csClassModel.setMethods(csMethodList);
                    csClassModel.setVariables(csVariableList);
                } else {
                    //TODO throw exception instead of logging
                    logger.debug("Conversion failed");
                }
            } catch (final ConversionFailedException e) {
                logger.debug("Exception: {}", e.getMessage());
            }

        } else {

            List<CSMethod> csMethodList = new ArrayList<CSMethod>();
            Imports imports = model.getImports();
            logger.info("Imports: {}", imports.toString());
            final BaseClassConverter baseClassConverter = new BaseClassConverter(model);
            try {
                if (baseClassConverter.convert()) {
                    csClassModel = baseClassConverter.getCsClassModel();
                    if (imports.getImports() != null) {
                        csClassModel.setUsings(this.dispatch(imports));
                    }
                    for (final Method method : model.getMethods()) {
                        csMethodList.add(this.dispatch(method));
                    }
                    csClassModel.setMethods(csMethodList);
                } else {
                    //TODO throw exception instead of logging
                    logger.debug("Conversion failed");
                }
            } catch (final ConversionFailedException e) {
                logger.debug("Exception: {}", e.getMessage());
            }

        }
        return csClassModel;
    }

    /**
     * This method calls converters for a given {@link JavaDoc} to be converted to
     * {@link CSXMLComment}
     *
     * @param model  The <code>JavaDoc</code> to be converted
     * @return  The resulting <code>CSXMLComment</code> from converting the JavaDoc
     */
    public CSXMLComment dispatch(final JavaDoc model) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    /**
     * This method calls converters for a given {@link Method} to convert it to {@link CSMethod}
     *
     * @param model  The <code>Method</code> to be converted
     * @return  An instance of <code>CSMethod</code> resulting f
     *         rom the conversion of the given <code>Method</code>
     */
    public CSMethod dispatch(final Method model) {
        CSMethod method = new CSMethod();
        List<CSVariable> variableList = new ArrayList<CSVariable>();
        final MethodConverter methodConverter = new MethodConverter(model);
        try {
            if (methodConverter.convert()) {
                method = methodConverter.getCsMethod();
            }

        } catch (final ConversionFailedException e) {
            logger.debug("Exception: {}", e.getMessage());
        }
        return method;
    }

    /**
     * This method calls converters for a given {@link Variable} to convert it to {@link CSVariable}
     *
     * @param model  The <code>Variable</code> to be converted
     * @return  An instance of <code>CSVariable</code> resulting from
     *         the conversion of the given <code>Variable</code>
     */
    public CSVariable dispatch(final Variable model) {
        CSVariable variable = new CSVariable();
        final VariableConverter variableConverter = new VariableConverter(model);
        try {
            if (variableConverter.convert()) {
                variable = variableConverter.getCsVariable();
            }
        } catch (final ConversionFailedException e) {
            logger.debug("Exception: {}", e.getMessage());
        }
        return variable;
    }

    /**
     * This method calls converters for a given {@link Imports} to convert it to {@link Usings}
     *
     * @param model  The <code>Imports</code> to be converted
     * @return  An instance of <code>Usings</code> resulting f
     *         rom the conversion of the given <code>Imports</code>
     */
    public Usings dispatch(final Imports model) {
        Usings usings = new Usings();
        final ImportsConverter importsConverter = new ImportsConverter(model);
        try {
            if (importsConverter.convert()) {
                usings = importsConverter.getUsings();
            }
        } catch (final ConversionFailedException e) {
            logger.debug("Exception: {}", e.getMessage());
        }
        logger.info("Usings: {}", usings.toString());
        return usings;
    }

}
